/*
 * This file is part of connotea-java.
 *
 * connotea-java is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * connotea-java is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package org.connotea;

import static org.apache.commons.lang.builder.ToStringBuilder.reflectionToString;

import java.io.Serializable;
import java.math.BigDecimal;

import org.apache.commons.lang.builder.CompareToBuilder;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

/**
 * Tag entity bean.
 * <p>
 * <em>Note that a bean of this class will only be fully populated when returned
 * as part of a call which explicitly returns tag instances.</em> When returned
 * as a field in a post, only <code>value</code> is available and all other
 * fields will be <code>null</code>. An early implementation of this class did
 * attempt lazy-loading of complete tag data on the basis of the
 * {@link #getValue()}, however this proved to be too intensive.
 * 
 * @author <a href="mailto:christopher.townson@googlemail.com">Christopher
 *         Townson</a>
 */
public final class Tag implements Comparable<Tag>, Serializable {

    private static final long serialVersionUID = 1L;

    private Long postCount;

    private BigDecimal usageScore;

    private Long userCount;

    private String value;

    /**
     * Default, no-argument constructor.
     */
    public Tag() {
        // do nothing
    }

    /**
     * Instantiate a tag with the specified value.
     * 
     * @param value the value to set
     */
    public Tag(String value) {
        setValue(value);
    }

    /**
     * Copy constructor.
     * 
     * @param tag the tag to copy
     */
    public Tag(Tag tag) {
        setPostCount(tag.getPostCount());
        setUsageScore(tag.getUsageScore());
        setUserCount(tag.getUserCount());
        setValue(tag.getValue());
    }

    /**
     * Comparability is based on value, usageScore, postCount, then userCount.
     * 
     * @see java.lang.Comparable#compareTo(java.lang.Object)
     */
    public int compareTo(Tag tag) {
        return new CompareToBuilder().append(value, tag.value).append(
                usageScore, tag.usageScore).append(postCount, tag.postCount)
                .append(userCount, tag.userCount).toComparison();
    }

    /**
     * Equality is based on value, usageScore, postCount, then userCount.
     * 
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof Tag)) {
            return false;
        }
        Tag tag = (Tag) obj;
        return new EqualsBuilder().append(value, tag.value).append(usageScore,
                tag.usageScore).append(postCount, tag.postCount).append(
                userCount, tag.userCount).isEquals();
    }

    /**
     * Returns the postCount. This is the number of times this tag has been
     * used.
     * 
     * @return the postCount
     */
    public Long getPostCount() {
        return postCount;
    }

    /**
     * Returns the usageScore. This is the usage score for this tag. This takes
     * account of how recently it was used, as well as how often.
     * 
     * @return the usageScore
     */
    public BigDecimal getUsageScore() {
        return usageScore;
    }

    /**
     * Returns the userCount. This is the number of users who have used this
     * tag.
     * 
     * @return the userCount
     */
    public Long getUserCount() {
        return userCount;
    }

    /**
     * Returns the value. This is the tag string value itself.
     * 
     * @return the value
     */
    public String getValue() {
        return value;
    }

    /**
     * HashCode is based on value, usageScore, postCount, then userCount.
     * 
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(value).append(usageScore).append(
                postCount).append(userCount).toHashCode();
    }

    /**
     * Sets the postCount.
     * 
     * @param postCount the postCount to set
     */
    public void setPostCount(Long postCount) {
        this.postCount = postCount;
    }

    /**
     * Sets the usageScore.
     * 
     * @param usageScore the usageScore to set
     */
    public void setUsageScore(BigDecimal usageScore) {
        this.usageScore = usageScore;
    }

    /**
     * Sets the userCount.
     * 
     * @param userCount the userCount to set
     */
    public void setUserCount(Long userCount) {
        this.userCount = userCount;
    }

    /**
     * Sets the value.
     * 
     * @param value the value to set
     */
    public void setValue(String value) {
        this.value = value;
    }

    /**
     * Pretty-prints the current object state.
     * 
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return reflectionToString(this);
    }
}
